package com.shihan.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.URI;

/**
 * @Description 注意导包：大多都是使用 springframework.amqp.rabbit 包中的对象
 * @Author shihan
 * @Date 2020/12/26 16:58
 * @Version 1.0
 */
@Configuration
public class RabbitMQConfig {

    /**
     * 配置 ConnectionFactory
     * @return
     */
    @Bean
    public ConnectionFactory connectionFactory(){
        // 使用 CachingConnectionFactory，类似于池化管理的连接
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setUri(URI.create("amqp://root:123456@192.168.66.129:5672/%2f"));
        return connectionFactory;
    }

    // 创建 RabbitTemplate
    // TODO 疑问1：参数中需要引用来自 IOC 容器中的对象，只需要在方法前面表上 @Autowired 即可，但是原理是啥？
    @Bean
    @Autowired
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate();
        rabbitTemplate.setConnectionFactory(connectionFactory);
        return rabbitTemplate;
    }

    // 创建 RabbitAdmin
    @Bean
    @Autowired
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    // 声明 Queue
    @Bean
    public Queue queue(){
        // 通过 QueueBuilder 来创建队列
        Queue queue = QueueBuilder.nonDurable("queue.anno.q01").build();
        return queue;
    }

    // 声明 Exchange
    @Bean
    public Exchange exchange(){
        // 不同类型的 Exchange，直接 new 即可；
        DirectExchange directExchange = new DirectExchange("exc.direct.anno.e01", false, false, null);
        return directExchange;
    }

    // 进行 Binding 绑定操作
    // TODO 疑问：
    //   1、如果我要声明多个 Queue 和 Exchange，需要做什么改动来区分这些 Queue 和 Exchange？
    //   2、如果我想要给一个 Exchange 绑定多个 Queue，参数应该怎么写，怎么准确的获取 IOC 中的 Queue 和 Exchange？
    //   3、如果我想要创建多个 Binding 关系，这时候应该怎么解决？
    // 因为现在只有一个 Queue 和一个 Exchange，所以这样直接从 IOC 中取是不会错乱的，正好把上面声明的那个 Queue 和 Exchange 进行绑定；
    @Bean
    @Autowired
    public Binding binding(Queue queue,Exchange exchange){
        // 绑定关系，也需要使用对应的 Builder 来帮我们实现；
        Binding binding = BindingBuilder.bind(queue).to(exchange).with("rk.direct.01").noargs();
        return binding;
    }

}
